#include "Global.h"

// Threads
DWORD  dwCaptureThread;
HANDLE hCaptureThread;

// Strings
const char* TIMEFORMAT = "%Y/%m/%d %I:%M:%S %p";

// Variables
int g_nNumberOfPackets = 0;

// Constants
const int CHUNK = 2048;//16384;

// Character Formats
CHARFORMAT cfNormal;

// Lists
CList <PACKET, PACKET&> PacketList;

// WinPCap variables
pcap_t *fp;

// Function definitions
/*****************************************************************************/
/*                                                                           */
/* strnstr                                                                   */
/*                                                                           */
/*****************************************************************************/
const u_char* strnstr(const u_char* strHaystack, const u_char* strNeedle, int nLen)
{
  int nLenOfNeedle = strlen((const char*)strNeedle);
  int i;
  const char* notUnsigned = (const char*)strHaystack;

  for (i = 0; i < nLen; i++)
  {
    if (i + nLenOfNeedle > nLen)
      return NULL;

    if (!strncmp(&notUnsigned[i], (const char*)strNeedle, nLenOfNeedle))
      return &strHaystack[i];
  }

  return NULL;
}

/*****************************************************************************/
/*                                                                           */
/* CopyBuffer                                                                */
/*                                                                           */
/*****************************************************************************/
u_char* CopyBuffer(u_char* strDest, const u_char* strSrc, int nBytesToCopy)
{
  for (int i = 0; i < nBytesToCopy; i++)
    strDest[i] = strSrc[i];
  
  return strDest;
}

/*****************************************************************************/
/*                                                                           */
/* ClearPacketList                                                           */
/*                                                                           */
/*****************************************************************************/
void ClearPacketList()
{
  g_nNumberOfPackets = 0;
  PacketList.RemoveAll();
}

/*****************************************************************************/
/*                                                                           */
/* Decompress                                                                */
/*                                                                           */
/*****************************************************************************/
int Decompress(const u_char* strStreamIn, int nStreamInLen, u_char* strStreamOut)
{
    int ret;
    unsigned have;
    z_stream strm;
    unsigned char in[CHUNK];
    unsigned char out[CHUNK];

    /* allocate inflate state */
    strm.zalloc = Z_NULL;
    strm.zfree = Z_NULL;
    strm.opaque = Z_NULL;
    strm.avail_in = 0;
    strm.next_in = Z_NULL;

    ret = inflateInit2(&strm, MAX_WBITS + 16);
    if (ret != Z_OK)
        return ret;

    strm.avail_in = nStreamInLen;
    CopyBuffer(in, strStreamIn, nStreamInLen);

    /* decompress until deflate stream ends or end of file */
    do {
        if (strm.avail_in == 0)
            break;
        strm.next_in = in;

        /* run inflate() on input until output buffer not full */
        do {
            strm.avail_out = CHUNK;
            strm.next_out = out;
            ret = inflate(&strm, Z_NO_FLUSH);
            assert(ret != Z_STREAM_ERROR);  /* state not clobbered */
            switch (ret) {
            case Z_NEED_DICT:
                ret = Z_DATA_ERROR;     /* and fall through */
            case Z_DATA_ERROR:
            case Z_MEM_ERROR:
                (void)inflateEnd(&strm);
                return ret;
            }
            have = CHUNK - strm.avail_out;
            CopyBuffer(strStreamOut + strm.total_out - have, out, have);
        } while (strm.avail_out == 0);

        /* done when inflate() says it's done */
    } while (ret != Z_STREAM_END);

    ret = strm.total_out;

    /* clean up and return */
    (void)inflateEnd(&strm);
    return ret;
}

/*****************************************************************************/
/*                                                                           */
/* FindRelatedPacket                                                         */
/*                                                                           */
/*****************************************************************************/
PACKET FindRelatedPacket(int nSourcePort)
{
  PACKET relatedPacket;
  POSITION rPosition = PacketList.GetHeadPosition();

  while (rPosition != NULL)
  {
    relatedPacket = PacketList.GetNext(rPosition);
    if ( (relatedPacket.nSourcePort == nSourcePort) && 
         (strnstr(relatedPacket.strPacketData, (const u_char*)"Content-Length", relatedPacket.nPacketLen) != NULL) )
      return relatedPacket;
  }

  // if it gets here, no packet was found
  relatedPacket.nPacketNo = 0;
  return relatedPacket;
}

/*****************************************************************************/
/*                                                                           */
/* GetKeyData                                                                */
/*                                                                           */
/*****************************************************************************/
int GetKeyData(const char* key, const u_char* pkt_data, int len)
{
  const u_char* pos;
//  u_char data[10];
  int i = 0;

  pos = strnstr(pkt_data, (const u_char*)key, len);
  if (pos == NULL)
    return 0;

  pos += (strlen(key) + 2); // move up 2 bytes because the data starts after the ':'
  if (pos[0] == '\"')
    pos++;

  return atoi((char*)pos);
}